#include "seqlist.h"
#include "printOut.h"				//自定义输出头文件

//显示用户信息
void ShowUserInfo(UserType userInfo)
{
	char buf[100] = "";
	sprintf(buf, "电话号码:%-26ld\n", userInfo.userId);
	PrintCenter(buf);
	sprintf(buf, "登录状态:%-26d\n", userInfo.state);
	PrintCenter(buf);
	sprintf(buf, "用户名  :%-26s\n", userInfo.userName);
	PrintCenter(buf);
	sprintf(buf, "密码    :%-27s\n", userInfo.password);
	PrintCenter(buf);
}

/*
	参数：
		lines 0：单行显示 1：多行显示
		contactInfo 联系人的信息
	功能：显示联系人信息
*/
void ShowContactInfo(int lines, ContactType contactInfo)
{
	char buf[100] = "";
	if(lines == 0)//单行显示
	{
		char buf[100] = "";
		sprintf(buf, "%-8s %-11ld %-5s %-3d %-20s %11ld\n", contactInfo.name, contactInfo.contactId, contactInfo.gender, contactInfo.age, contactInfo.addres, contactInfo.userId);
		PrintCenter(buf);
	}
	else//多行显示
	{
		sprintf(buf, "联系人姓名:%-80s\n", contactInfo.name);
		PrintCenter(buf);
		sprintf(buf, "联系电话  :%-82ld\n", contactInfo.contactId);
		PrintCenter(buf);
		sprintf(buf, "性别      :%-83s\n", contactInfo.gender);
		PrintCenter(buf);
		sprintf(buf, "年龄      :%-83d\n", contactInfo.age);
		PrintCenter(buf);
		sprintf(buf, "家庭住址  :%-82s\n\n", contactInfo.addres);
		PrintCenter(buf);
	}
}

/*
	功能：遍历顺序表sequence顺序list表
	参数：	 SeqListType *p	p顺序表在内存中的地址
			argType 0 显示用户表信息， 1显示通信录表信息
	返回值：null
*/
void ShowSeqlist(const SeqListType * const p, int argType) 
{
	if(p->last == -1)
	{
		return;
	}
	//参数检验
	if (p == NULL)
	{
		printf("参数p,非NULL错误!\n");
		return ;
	}
	if(argType == 1)
	{
		char buf[100] = "";
		sprintf(buf, "       联系人姓名  联系电话   性别 年龄 家庭住址              用户ID\n");
		PrintCenter(buf);
	}
	
	//从下标0开始顺序打印顺序表中的元素
	for (int i = 0; i <= p->last; i++) {
		if(argType == 0)
		{
			ShowUserInfo(p->data[i].userInfo);
		}
		else
		{
			ShowContactInfo(0, p->data[i].contactInfo);
		}
	}
	printf("\n");
}

/*
	功能：创建一个空的顺序表
	参数：void
	返回值：返回的是申请空间的首地址
*/
SeqListType *CreateEpSeqlist() {
	PSeqListType p = (PSeqListType)malloc(sizeof(SeqListType));//注意内存泄漏！
	
	//检查开辟空间是否成功
	if (p == NULL)
	{
		printf("开辟空间失败!\n");
		return NULL;
	}

	p->data = (PElementType)malloc(SEQ_SIZE * sizeof(ElementType));
	if (p->data == NULL)
	{
		printf("开辟空间失败!\n");
		free(p);
		p == NULL;
		return NULL;
	}

	p->last = -1;
	p->capacity = SEQ_SIZE;//初始大小
	return p;
}

/*
	功能：顺序表扩展容量
	参数：seqlist_t *p	p顺序表在内存中的地址,非空NULL
		 int newCapacity 顺序表新的容量
	返回值：扩容成功返回1，失败返回-1
*/
int ExpendSeqlist(SeqListType *p, int newCapacity)
{
	PElementType newData = (PElementType)realloc(p->data, newCapacity * sizeof(ElementType));
	if (newData == NULL) 
	{
		return -1;
	}
	p->data = newData;
	p->capacity = newCapacity;//初始大小
	return 1;
}

/*
	功能：向顺序表的指定位置插入数据
	参数：seqlist_t *p	p顺序表在内存中的地址,非空NULL
		  int post		post第几个位置，下标从0开始，范围[0, last + 1] last 最后一个有效元素的下标
		  ElementType data		data插入的数据
	返回值：插入是否成功，成功返回1，失败返回-1,对数据的改动操作时,应当判断执行操作是否成功
*/
int InsertIntoSeqlist(SeqListType *p, int post, ElementType data) {
	//参数检验
	if (p == NULL) {
		printf("参数p,非NULL错误!\n");
		return -1;//失败
	}
	if (post < 0 || post > p->last + 1) {
		printf("参数post,范围错误!\n");
		return -1;//失败
	}
	if (IsFullSeqlist(p)) {
		int res = ExpendSeqlist(p, p->capacity * 2);//扩展2倍容量
		if(res == -1)
		{
			return -1;
		}
	}

	//从最后一位元素last后移，方向向前遍历，直到post结束
	for (int i = p->last; i >= post; i--)//将下标i的操作数后移一位
		p->data[i + 1] = p->data[i];
	
	//插入元素
	p->data[post] = data;
	p->last++;//单目右运算符，自左向右结合

	return 1;//成功
}

/*
	功能：判断顺序表是否为满
	参数：seqlist_t *p	p顺序表在内存中的地址
	返回值：满返回1 未满或参数失败返回０
*/
int IsFullSeqlist(const SeqListType * const p) {
	//参数检验
	if (p == NULL) {
		printf("参数p,非NULL错误!\n");
		return 0;//失败
	}

	if (p->last < p->capacity - 1)
		return 0;//未满
	return 1;	//满
}

/*
	功能：判断顺序表是否为空
	参数：seqlist_t *p	p顺序表在内存中的地址
	返回值：空返回1 非空或参数失败返回０
*/
int IsEpSeqlist(const SeqListType * const p) {
	//参数检验
	if (p == NULL) {
		printf("参数p,非NULL错误!\n");
		return 0;//失败
	}

	if (p->last == -1)
		return 1; //空
	return 0;	//非空
}

/*
	功能：删除顺序表中指定位置的数据post删除位置
	参数：seqlist_t *p	p顺序表在内存中的地址
		  int post		post第几个位置，下标从0开始，范围[0, last] last 最后一个有效元素的下标
	返回值：删除是否成功，成功返回1，失败返回-1,对数据的改动操作时,应当判断执行操作是否成功
*/
int DeletePostSeqlist(SeqListType *p, int post) {
	//参数检验
	if (p == NULL) {
		printf("参数p,非NULL错误!\n");
		return -1;//失败
	}
	if (post < 0 || post > p->last) {
		printf("参数post,范围错误!\n");
		return -1;//失败
	}
	if (IsEpSeqlist(p)) {
		printf("顺序表空!\n");
		return -1;//失败
	}

	//从(post+1)下标开始前移元素，向后遍历，直到last
	for (int i = post + 1; i <= p->last; i++) //将下标i的操作数前移一位
		p->data[i - 1] = p->data[i];
	
	//删除元素
	p->last--;//单目右运算符，自左向右结合
	return 1;//成功
}

/*
	功能：清空顺序表
	参数：seqlist_t *p	p顺序表在内存中的地址
	返回值：null
*/
void ClearSeqList(SeqListType *p) {
	//参数检验
	if (p == NULL) {
		printf("参数p,非NULL错误!\n");
		return;//失败
	}

	//删除所有元素
	p->last = -1;
}

/*
	功能：修改指定位置的数据
	参数：seqlist_t *p	p顺序表在内存中的地址
		  int post		post被修改的位置，下标从0开始，范围[0, last] last 最后一个有效元素的下标
		  ElementType data		data修改成的数据
	返回值：修改是否成功，成功返回1，失败返回-1,对数据的改动操作时,应当判断执行操作是否成功
*/
int ChangePostSeqList(SeqListType *p, int post, ElementType data) {
	//参数检验
	if (p == NULL) {
		printf("参数p,非NULL错误!\n");
		return -1;//失败
	}
	if (post < 0 || post > p->last) {
		printf("参数post,范围错误!\n");
		return -1;//失败
	}

	//修改元素
	p->data[post] = data;

	return 1;//成功
}

/*
	功能：查找指定数据出现的位置
	参数：seqlist_t *p	p顺序表在内存中的地址
		  ElementType data		data代表被查找的数据
	返回值：返回查找第一个数的位置下标,参数错误返回-1, 未找到元素返回-1
*/
int SearchDataSeqList(const SeqListType * const p, ElementType data) {
	//参数检验
	if (p == NULL) {
		printf("参数p,非NULL错误!\n");
		return -1;//失败
	}

	//从下标0开始从前向后遍历匹配元素值，相等则返回此时下标,直到last结束
	for(int i = 0; i <= p->last; i++){
		if (memcmp(&p->data[i], &data, sizeof(ElementType)) == 0)
			return i;//找到元素
	}
	return -1;//未找到元素
}

/*
	功能：释放堆区开辟空间
	参数：seqlistPtr_t *q q为指向堆区内存地址指针p的地址
*/
void MyFree(PSeqListType *q) 
{
	if((*q)->data != NULL)
	{
		free((*q)->data);
		(*q)->data = NULL;
	}
	
	if(*q != NULL)
	{
		free(*q);
		*q = NULL;
	}
}

/*
	功能：对顺序表进行排序
	参数：seqlist_t *p	顺序表在内存中的地址
*/
//void MySort(SeqListType *p) {
//	//冒泡排序
//	int n = p->last + 1;	//n为元素个数
//	for (int i = 0; i < n - 1; i++) {
//		for (int j = 0; j < n - 1 - i; j++) {
//			if (p->data[j] > p->data[j + 1]) {
//				p->data[j] = p->data[j] ^ p->data[j + 1];
//				p->data[j + 1] = p->data[j] ^ p->data[j + 1];
//				p->data[j] = p->data[j] ^ p->data[j + 1];
//			}
//		}
//	}
//}